package com.wxapp.common.core.mybatis.mysql;

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils;
import com.wxapp.common.constant.enums.SqlMethodEnum;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;

import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author lgl
 * @Description
 * @Datetime 2022/4/25 15:19
 * @Modified By
 */
public class BatchSaveOrUpdate extends AbstractMethod {
    @Setter
    @Accessors(chain = true)
    private Predicate<TableFieldInfo> predicate;
    private SqlMethodEnum sqlMethod;
    public BatchSaveOrUpdate(SqlMethodEnum sqlMethod) {
        super(sqlMethod.getMethod());
        this.sqlMethod=sqlMethod;
    }

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        List<TableFieldInfo> fieldList = tableInfo.getFieldList();
        String insertSqlColumn = getKeySqlColumn(tableInfo, false) + filterTableFieldInfo(fieldList, predicate, TableFieldInfo::getInsertSqlColumn, EMPTY);
        String columnScript = LEFT_BRACKET + insertSqlColumn.substring(0, insertSqlColumn.length() - 1) + RIGHT_BRACKET;
        String insertSqlProperty = getKeySqlProperty(tableInfo, ENTITY_DOT, false) + this.filterTableFieldInfo(fieldList, predicate, i -> i.getInsertSqlProperty(ENTITY_DOT), EMPTY);
        insertSqlProperty = LEFT_BRACKET + insertSqlProperty.substring(0, insertSqlProperty.length() - 1) + RIGHT_BRACKET;
        String valuesScript = SqlScriptUtils.convertForeach(insertSqlProperty, "list", null, ENTITY, COMMA);
        String sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), columnScript, valuesScript);
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
        return this.addUpdateMappedStatement(mapperClass, modelClass, sqlSource);
    }

    private String getKeySqlProperty(TableInfo tableInfo, final String prefix, final boolean newLine) {
        String newPrefix = prefix == null ? "" : prefix;
        if (tableInfo.havePK()) {
            String keyColumn = SqlScriptUtils.safeParam(newPrefix + tableInfo.getKeyProperty()) + ",";
            return keyColumn;
        } else {
            return "";
        }
    }

    private String getKeySqlColumn(TableInfo tableInfo, final boolean newLine) {
        if (tableInfo.havePK()) {
            return tableInfo.getKeyProperty() + ",";
        } else {
            return "";
        }
    }

    protected String filterTableFieldInfo(List<TableFieldInfo> fieldList, Predicate<TableFieldInfo> predicate, Function<TableFieldInfo, String> function, String joiningVal) {
        Stream<TableFieldInfo> infoStream = fieldList.stream();
        return predicate != null ? infoStream.filter(predicate).map(function).collect(Collectors.joining(joiningVal)) : infoStream.map(function).collect(Collectors.joining(joiningVal));
    }
}
